package com.rfid.tool;

import com.rfid.domain.RfidEpc;
import com.rfid.domain.RfidOrder;
import com.rfid.domain.RfidRecord;
import com.rfid.mapper.RfidEpcMapper;
import com.rfid.mapper.RfidOrderMapper;
import com.rfid.mapper.RfidRecordMapper;
import com.rfid.service.IRfidRecordService;
import gnu.io.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.server.PortInUseException;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.TooManyListenersException;


/**
 * ComX类的功能是对COM1串口操作
 */
@Component
public class ComX implements SerialPortEventListener {

    /**
     * 向COM1写入数据
     * @param str
     */
    public void Writer(SerialPort serialCom,String str){
        try {

            //4.往串口写数据（使用串口对应的输出流对象）
            //4.1.获取串口的输出流对象
            OutputStream outputStream = serialCom.getOutputStream();

            //4.2.通过串口的输出流向串口写数据“Hello World!”：
            //使用输出流往串口写数据的时候必须将数据转换为byte数组格式或int格式，
            //当另一个串口接收到数据之后再根据双方约定的规则，对数据进行解码。
            byte[] bytes = str.getBytes();
            outputStream.write(bytes);
            outputStream.flush();
            //4.3.关闭输出流
            outputStream.close();

            //5.关闭串口
            serialCom.close();
        } catch (IOException e) {
            //如果获取输出流失败，则抛出该异常
            e.printStackTrace();
        }
    }

    /**
     * 轮询模式隔一段时间读取数据
     */
    public void Read(){
        //1.定义变量
        CommPortIdentifier com1 = null;//未打卡的端口
        SerialPort serialCom1 = null;//打开的端口
        InputStream inputStream = null;//端口输入流

        try{
            //2.获取并打开串口COM21
            com1 = CommPortIdentifier.getPortIdentifier("COM1");
            serialCom1 = (SerialPort) com1.open("ComListener", 1000);
            //3.获取串口的输入流对象
            inputStream = serialCom1.getInputStream();

            //4.从串口读入数据
            //定义用于缓存读入数据的数组
            byte[] cache = new byte[1024];
            //记录已经到达串口COM21且未被读取的数据的字节（Byte）数。
            int availableBytes = 0;
            boolean s=true;
            //无限循环，每隔20毫秒对串口COM21进行一次扫描，检查是否有数据到达
            while(s){
                //获取串口COM21收到的可用字节数
                availableBytes = inputStream.available();
                //如果可用字节数大于零则开始循环并获取数据
                while(availableBytes > 0){
                    //从串口的输入流对象中读入数据并将数据存放到缓存数组中
                    inputStream.read(cache);
                    StringBuilder str = new StringBuilder();
                    //将获取到的数据进行转码并输出
                    for(int j = 0;j < cache.length && j < availableBytes; j++){
                        //因为COM11口发送的是使用byte数组表示的字符串，
                        //所以在此将接收到的每个字节的数据都强制装换为char对象即可，
                        //这是一个简单的编码转换，读者可以根据需要进行更加复杂的编码转换。


                        //调用一个方法 对数据处理
                        //数据类型:53.268435456.16777216.68719476736
                        String c = String.valueOf((char) cache[j]);
                        str.append(c);
                    }
                    PortReturn(serialCom1,str);
                    s=false;
                    //更新循环条件
                    availableBytes = inputStream.available();
                }
                //让线程睡眠20毫秒
                Thread.sleep(200);
            }
        }catch(InterruptedException e){
            e.printStackTrace();
        }catch (NoSuchPortException e) {
            //找不到串口的情况下抛出该异常
            e.printStackTrace();
        } catch (PortInUseException e) {
            //如果因为端口被占用而导致打开失败，则抛出该异常
            e.printStackTrace();
        } catch (IOException e) {
            //如果获取输出流失败，则抛出该异常
            e.printStackTrace();
        } catch (gnu.io.PortInUseException e) {
            throw new RuntimeException(e);
        }
    }





    private static RfidEpcMapper EpcMapper;
    @Autowired
    private RfidEpcMapper rfidEpcMapper;

    private static RfidOrderMapper OrderMapper;
    @Autowired
    RfidOrderMapper rfidOrderMapper;

    @Autowired
    private IRfidRecordService rfidRecordService;

    private static IRfidRecordService RecordService;

    @PostConstruct
    public void init(){
        EpcMapper =this.rfidEpcMapper;
        OrderMapper=this.rfidOrderMapper;
        RecordService=this.rfidRecordService;
    }







    public void PortReturn(SerialPort serialCom,StringBuilder epc){
        //分解epc码 String id
        //53    .268435456  .16777216   .68719476736

        //String epcVersion
        String epcVersion=epc.substring(0,epc.indexOf("."));

        //String epcSupplier
        String substring = epc.substring(epc.indexOf(("."))+1, epc.length());
        String epcSupplier=substring.substring(0,substring.indexOf("."));

        //String epcProduct
        String substring2 = substring.substring(substring.indexOf(".")+1, substring.length());
        String epcProduct=substring2.substring(0, substring2.indexOf("."));

        //String epcCategory
        String  epcCategory = substring2.substring(substring2.indexOf(".")+1, substring2.length());

        //查询epc对应的物品订单信息
        RfidEpc rfidEpc=new RfidEpc();
        rfidEpc.setEpcVersion(epcVersion);
        rfidEpc.setEpcSupplier(epcSupplier);
        rfidEpc.setEpcProduct(epcProduct);
        rfidEpc.setEpcCategory(epcCategory);
        List<RfidEpc> rfidEpcs = EpcMapper.selectRfidEpcList(rfidEpc);

        if (rfidEpcs.size()!=0){
            RfidEpc rfidEpc1 = rfidEpcs.get(0);
            Long id = rfidEpc1.getId();
            //查询epc对应的物品订单信息
            RfidOrder rfidOrder = OrderMapper.selectRfidOrderById(id);
            ComX com1Writer=new ComX();
            String str="1";
            if (rfidOrder.getStatus()!=1){
                System.out.println("物品很久以前已经出库或未支付订单！");
            }
            //如果实际存入和取出时间为空
            if (rfidOrder.getSaveTime()==null && rfidOrder.getGetTime()==null){
                //---》》记录为存入操作
                rfidOrder.setSaveTime(new Date());
                int i = OrderMapper.updateRfidOrder(rfidOrder);

                //添加记录
                RfidRecord rfidRecord=new RfidRecord();
                rfidRecord.setType(1);
                rfidRecord.setProduct(String.valueOf(rfidOrder.getpId()));
                rfidRecord.setUpdataBy(1L);
                int i1 =RecordService.insertRfidRecord(rfidRecord);

                if(i!=0 && i1==1){
                    System.out.println("物品入库！");
                    str="0";
                }

            }
            //如果存入不为空  和 取出时间为空
            else if(rfidOrder.getSaveTime()!=null && rfidOrder.getGetTime()==null){
                //----》》记录为取出操作
                rfidOrder.setGetTime(new Date());
                int i = OrderMapper.updateRfidOrder(rfidOrder);

                RfidRecord rfidRecord=new RfidRecord();
                rfidRecord.setType(0);
                rfidRecord.setProduct(String.valueOf(rfidOrder.getpId()));
                rfidRecord.setUpdataBy(1L);
                rfidRecord.setUpdataTime(new Date());

                int i1 = RecordService.insertRfidRecord(rfidRecord);
                if(i!=0&& i1==1){
                    System.out.println("物品出库！");
                    str="0";
                }
            }
            //都为空返回异常
            else {
                //----》》异常情况
                System.out.println("物品很久以前已经出库");
            }
            com1Writer.Writer(serialCom,str);
        }
    }

    /**
     * 监听模式有数据在读取
     */
    //1.定义变量
    CommPortIdentifier com1 = null;//未打开的端口
    SerialPort serialCom1 = null;//打开的端口
    InputStream inputStream = null;//输入流

    //2.构造函数：
    //实现初始化动作：获取串口COM1、打开串口、获取串口输入流对象、为串口添加事件监听对象
    public void ComX(){
        try {
            //获取串口、打开窗串口、获取串口的输入流。
            com1 = CommPortIdentifier.getPortIdentifier("COM1");
            serialCom1 = (SerialPort) com1.open("ComEventListener", 1000);
            inputStream = serialCom1.getInputStream();
            //向串口添加事件监听对象。
            serialCom1.addEventListener((SerialPortEventListener) this);
            //设置当端口有可用数据时触发事件，此设置必不可少。
            serialCom1.notifyOnDataAvailable(true);
        } catch (NoSuchPortException | PortInUseException | IOException | TooManyListenersException e) {
            e.printStackTrace();
        } catch (gnu.io.PortInUseException e) {
            throw new RuntimeException(e);
        }
    }

    //重写继承的监听器方法
    @Override
    public void serialEvent(SerialPortEvent event) {
        //定义用于缓存读入数据的数组
        byte[] cache = new byte[1024];
        //记录已经到达串口COM21且未被读取的数据的字节（Byte）数。
        int availableBytes = 0;
        //如果是数据可用的时间发送，则进行数据的读写
        if(event.getEventType() == SerialPortEvent.DATA_AVAILABLE){
            try {
                availableBytes = inputStream.available();
                while(availableBytes > 0){
                    inputStream.read(cache);
                    for(int i = 0; i < cache.length && i < availableBytes; i++){
                        //解码并输出数据
                        System.out.print((char)cache[i]);
                    }
                    availableBytes = inputStream.available();
                }
                System.out.println();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    //在main方法中创建类的实例
    public static void main(String[] args) {
        new ComX();
    }
}

